﻿#pragma once
#include "yzrutil.h"
#include "lang/Math.h"
namespace yzrilyzr_dsp{
	enum BoundOption{
		ZERO,
		LOOP,
		PING_PONG,
		AS_BOUND
	};
	EBCLASS(InterpolateFunction){
	public:
	template<typename T>
	static inline u_index getIndex(T * arr, u_index index, u_index boundStart, u_index boundEnd, BoundOption option){
		// 首先检查是否在边界内
		if(index >= boundStart && index <= boundEnd){
			return index;
		}
		u_index boundSize=(boundEnd - boundStart + 1);
		switch(option){
			case ZERO:
				return boundSize; // 返回超出边界的值
			case LOOP:
			{
				// 使用有符号运算处理负数
				u_index offset=index - boundStart;
				u_index wrapped=offset % boundSize;
				// 处理负数的模运算
				if(wrapped < 0){
					wrapped+=boundSize;
				}
				return boundStart + wrapped;
			}
			case PING_PONG:
			{
				u_index offset=index - boundStart;
				u_index period=2 * boundSize - 2;
				// 处理负偏移量
				u_index wrapped=offset % period;
				if(wrapped < 0){
					wrapped+=period;
				}
				if(wrapped < boundSize){
					return boundStart + (u_index)wrapped;
				} else{
					return boundEnd - (u_index)(wrapped - boundSize);
				}
			}
			case AS_BOUND:
				// 截断到最近的边界
				if(index < boundStart){
					return boundStart;
				} else{
					return boundEnd;
				}
			default:
				// 默认使用AS_BOUND
				if(index < boundStart){
					return boundStart;
				} else{
					return boundEnd;
				}
		}
	}

	// 重载版本：处理ZERO选项的辅助函数
	template<typename T>
	static inline T getValueWithZero(T * arr, u_index index, u_index boundStart, u_index boundEnd, BoundOption option){
		u_index actualIndex=getIndex(arr, index, boundStart, boundEnd, option);
		if(option == ZERO && actualIndex > boundEnd){
			return T(0); // 返回0值
		} else{
			return arr[actualIndex];
		}
	}
	/*
	y0 i-1
	y1 i
	y2 i+1
	y3 i+2
	*/
	static inline u_sample cubicSpline(u_sample index, u_index indexI, u_sample y0, u_sample y1, u_sample y2, u_sample y3){
		u_sample f=index - indexI;
		u_sample f2=f * f;
		u_sample f3=f2 * f;
		u_sample v1=0.5;
		u_sample v2=1.5;
		u_sample v3=2.5;
		u_sample v4=2;
		u_sample a=(-v1 * y0) + (v2 * y1) - (v2 * y2) + (v1 * y3);
		u_sample b=y0 - (v3 * y1) + (v4 * y2) - (v1 * y3);
		u_sample c=(-v1 * y0) + (v1 * y2);
		u_sample d=y1;
		return a * f3 + b * f2 + c * f + d;
	}
	/*
	y0 i
	y1 i+1
	*/
	static inline u_sample linear(u_sample index, u_index indexI, u_sample y0, u_sample y1){
		u_sample x=index - indexI;
		return y0 + (y1 - y0) * x;
	}
	static inline u_sample PCHIPSlope(u_sample y0, u_sample y1, u_sample y2, u_sample y3){
		u_sample h0=y1 - y0;
		u_sample h1=y2 - y1;
		u_sample h2=y3 - y2;

		// 计算加权平均斜率（避免除以零）
		u_sample d0=(h0 != 0 && h1 != 0)?(h0 + h1) / 2:0;
		u_sample d1=(h1 != 0 && h2 != 0)?(h1 + h2) / 2:0;
		u_sample zero=0;
		u_sample h1Mul3=3.0 * h1;
		// 调整斜率以保持单调性
		if(h1 > 0){
			d0=yzrilyzr_lang::Math::max(zero, yzrilyzr_lang::Math::min(d0, h1Mul3));
			d1=yzrilyzr_lang::Math::max(zero, yzrilyzr_lang::Math::min(d1, h1Mul3));
		} else if(h1 < 0){
			d0=yzrilyzr_lang::Math::min(zero, yzrilyzr_lang::Math::max(d0, h1Mul3));
			d1=yzrilyzr_lang::Math::min(zero, yzrilyzr_lang::Math::max(d1, h1Mul3));
		} else{
			d0=0;
			d1=0;
		}
		return d1; // 返回右侧斜率
	}

	// PCHIP 插值函数
	static inline u_sample PCHIP(u_sample x, u_sample x0, u_sample x1, u_sample y0, u_sample y1, u_sample m0, u_sample m1){
		u_sample h=x1 - x0;
		u_sample t=(x - x0) / h;
		u_sample t2=t * t;
		u_sample t3=t2 * t;
		return y0 * (2 * t3 - 3 * t2 + 1) +
			y1 * (-2 * t3 + 3 * t2) +
			m0 * h * (t3 - 2 * t2 + t) +
			m1 * h * (t3 - t2);
	}
	// Akima 斜率计算（基于局部5个点）
	static inline u_sample akimaSlope(u_sample y_prev2, u_sample y_prev1, u_sample y0, u_sample y1, u_sample y2){
		// 计算相邻点的差分
		u_sample m0=y_prev1 - y_prev2;
		u_sample m1=y0 - y_prev1;
		u_sample m2=y1 - y0;
		u_sample m3=y2 - y1;

		// 计算权重
		u_sample w1=std::abs(m3 - m2);
		u_sample w2=std::abs(m1 - m0);

		// 避免除以零
		if(w1 + w2 == 0) return (m1 + m2) / 2;
		return (w1 * m1 + w2 * m2) / (w1 + w2);
	}

	// Akima 插值函数
	static inline u_sample akima(u_sample x, u_sample x0, u_sample x1, u_sample y0, u_sample y1, u_sample m0, u_sample m1){
		u_sample h=x1 - x0;
		u_sample t=(x - x0) / h;
		u_sample t2=t * t;
		u_sample t3=t2 * t;
		return y0 * (1 - 3 * t2 + 2 * t3) +
			y1 * (3 * t2 - 2 * t3) +
			m0 * h * (t - 2 * t2 + t3) +
			m1 * h * (-t2 + t3);
	}
	static inline u_sample sincInterpolate(const u_sample * src, u_index srcLen, u_sample pos, u_index taps){
		u_sample result=0.0;
		u_index start=yzrilyzr_lang::Math::max((u_index)0, (u_index)pos - taps / 2);
		u_index end=yzrilyzr_lang::Math::min(srcLen - 1, (u_index)pos + taps / 2);

		for(u_index i=start; i <= end; i++){
			u_sample delta=pos - i;
			u_sample sinc_val=(delta == 0)?1.0:std::sin(yzrilyzr_lang::Math::PI * delta) / (yzrilyzr_lang::Math::PI * delta);
			// 加窗（如Kaiser窗）减少吉布斯现象
			u_sample window=0.5 - 0.5 * std::cos(2.0 * yzrilyzr_lang::Math::PI * (i - start) / (end - start));
			result+=src[i] * sinc_val * window;
		}
		return result;
	}

	};
}